//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

#include "Physics2D/Objects/PhysicsObject.h"

namespace Engine
{
namespace Physics2D
{

	//
	// Shape Utils
	//

	struct ShapeUtils
	{
	// types
	public:
		typedef uni_array< const vec2 >			point_array_t;
		typedef uni_array< const line2d >		line_array_t;
		typedef uni_array< const vec2 >			vectices_t;


	// methods
	public:

		static bool AddLineStrip (PhysicsObject &obj, const point_array_t &points, const b2FixtureDef &fixture = b2FixtureDef())
		{
			CHECK_ERR( points.Count() > 1 );
			
			b2EdgeShape shape;

			b2FixtureDef sd = fixture;
			sd.shape		= &shape;
			sd.userData		= &obj;

			for (usize i = 0; i+1 < points.Count(); ++i)
			{
				shape.Set( Utils::Vec2( points[i] ), Utils::Vec2( points[i+1] ) );
				obj.GetBody()->CreateFixture( &sd );
			}
			return true;
		}


		static bool AddLines (PhysicsObject &obj, const line_array_t &lines, const b2FixtureDef &fixture = b2FixtureDef())
		{
			CHECK_ERR( not lines.Empty() );
			
			b2EdgeShape shape;

			b2FixtureDef sd = fixture;
			sd.shape		= &shape;
			sd.userData		= &obj;

			FOR( i, lines )
			{
				shape.Set( Utils::Vec2( lines[i].Begin() ), Utils::Vec2( lines[i].End() ) );
				obj.GetBody()->CreateFixture( &sd );
			}
			return true;
		}


		static bool AddArc (PhysicsObject &obj, const vec2 &center, float radius, float startAngle,
							float angle, uint segments, const b2FixtureDef &fixture = b2FixtureDef())
		{
			if ( segments < 2 )
				segments = 4;

			array< vec2 >	points( segments );

			for (uint i = 0; i < segments; ++i)
			{
				points[i] = center + radius * SinCos( startAngle + angle * float(i) / segments ).yx();
			}

			return AddLineStrip( obj, points, fixture );
		}


		static bool AddVertices (PhysicsObject &obj, const vectices_t &verts, const b2FixtureDef &fixture = b2FixtureDef())
		{
			b2PolygonShape	poly;
			poly.Set( Utils::Vec2Ptr( verts.ptr() ), verts.Count() );

			b2FixtureDef	sd = fixture;
			sd.shape		= &poly;
			sd.userData		= &obj;
			
			obj.GetBody()->CreateFixture( &sd );
			return true;
		}


		static bool AddBox (PhysicsObject &obj, const vec2 &size, const b2FixtureDef &fixture = b2FixtureDef())
		{
			b2PolygonShape shape;
			shape.SetAsBox( size.x, size.y );
			
			b2FixtureDef	sd = fixture;
			sd.shape		= &shape;
			sd.userData		= &obj;
			
			obj.GetBody()->CreateFixture( &sd );
			return true;
		}


		static bool AddBox (PhysicsObject &obj, const vec2 &size, const vec2 &center, float angleRad,
							const b2FixtureDef &fixture = b2FixtureDef())
		{
			b2PolygonShape shape;
			shape.SetAsBox( size.x, size.y, Utils::Vec2( center ), angleRad );
			
			b2FixtureDef	sd = fixture;
			sd.shape		= &shape;
			sd.userData		= &obj;
			
			obj.GetBody()->CreateFixture( &sd );
			return true;
		}


		static bool AddCircle (PhysicsObject &obj, float radius, const vec2 &center, const b2FixtureDef &fixture = b2FixtureDef())
		{
			b2CircleShape shape;
			shape.m_radius	= radius;
			shape.m_p		= Utils::Vec2( center );
			
			b2FixtureDef	sd = fixture;
			sd.shape		= &shape;
			sd.userData		= &obj;
			
			obj.GetBody()->CreateFixture( &sd );
			return true;
		}
	};


}	// Physics2D
}	// Engine